package com.hx.controller;

import com.google.common.util.concurrent.RateLimiter;
import com.hx.service.OrderService;
import com.hx.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

@RestController
@Slf4j
@RequestMapping("/stock")
public class StockController {

    @Autowired
    private OrderService orderService;

    @Autowired
    private UserService userService;

    //创建令牌桶限流 一次只放行5个人
    private RateLimiter rateLimiter = RateLimiter.create(5);

    /**
     * 使用悲观锁解决超卖现象
     * @param id
     * @return
     */
    @GetMapping("/kill0/{id}")
    public String kill0(@PathVariable("id") Integer id){

        try{
            synchronized (this){
                log.info("秒杀商品的id:{}",id);
                Integer orderId = orderService.kill0(id);
                return "秒杀成功，订单id为:"+orderId;
            }

        }catch (Exception e){

            log.error("秒杀商品id:{}时失败！",id);
            e.printStackTrace();
            return e.getMessage();

        }
    }

    /**
     * 使用乐观锁解决超卖现象
     * @param id
     * @return
     */
    @GetMapping("/kill1/{id}")
    public String kill1(@PathVariable("id") Integer id){

        try{
                log.info("秒杀商品的id:{}",id);
                Integer orderId = orderService.kill1(id);
                return "秒杀成功，订单id为:"+orderId;

        }catch (Exception e){

            log.error("秒杀商品id:{}时失败！",id);
            e.printStackTrace();
            return e.getMessage();

        }
    }

    /**
     * 使用乐观锁+令牌桶限流解决超卖现象
     * @param id
     * @return
     */
    @GetMapping("/kill2/{id}")
    public String kill2(@PathVariable("id") Integer id){

        try{

            if (!rateLimiter.tryAcquire(1, TimeUnit.SECONDS)){
                log.error("当前秒杀活动过于火爆，请重试！");
                return "抢购失败，请重试！";
            }

            log.info("秒杀商品的id:{}",id);
            Integer orderId = orderService.kill1(id);
            return "秒杀成功，订单id为:"+orderId;

        }catch (Exception e){

            log.error("秒杀商品id:{}时失败！",id);
            e.printStackTrace();
            return e.getMessage();

        }
    }

    /**
     * 使用乐观锁+限流+redis超时解决超卖现象
     * @param id
     * @return
     */
    @GetMapping("/kill3/{id}")
    public String kill3(@PathVariable("id") Integer id){

        try{

            if (!rateLimiter.tryAcquire(3, TimeUnit.SECONDS)){
                log.error("当前秒杀活动过于火爆，请重试！");
                return "抢购失败，请重试！";
            }

            log.info("秒杀商品的id:{}",id);
            Integer orderId = orderService.kill3(id);
            return "秒杀成功，订单id为:"+orderId;

        }catch (Exception e){

            log.error("秒杀商品id:{}时失败！",id);
            e.printStackTrace();
            return e.getMessage();

        }
    }

    /**
     * 生成md5
     * @param stockId
     * @param userId
     * @return
     */
    @RequestMapping("/md5/{stockId}/{userId}")
    public String getMd5(@PathVariable("stockId") Integer stockId,
                         @PathVariable("userId") Integer userId){

        String md5Value ;
        try {
           md5Value = orderService.getMd5(stockId, userId);
        }catch (Exception e){
            log.error("获取mg5失败！");
            e.printStackTrace();
            return "获取md5失败:"+e.getMessage();
       }

        return "获取md5成功:"+md5Value;

    }

    /**
     * 乐观锁+redis+限流+隐藏接口token 实现秒杀
     * @param stockId
     * @return
     */
    @GetMapping("/kill5/{stockId}/{userId}/{md5Value}")
    public String kill5(@PathVariable("stockId") Integer stockId,
                        @PathVariable("userId") Integer userId,
                        @PathVariable("md5Value") String md5Value){

        try{

            if (!rateLimiter.tryAcquire(3, TimeUnit.SECONDS)){
                log.error("当前秒杀活动过于火爆，请重试！");
                return "抢购失败，请重试！";
            }

            log.info("秒杀商品的id:{}",stockId);
            Integer orderId = orderService.kill5(stockId,userId,md5Value);
            return "秒杀成功，订单id为:"+orderId;

        }catch (Exception e){

            log.error("用户{}秒杀商品id:{}时失败！",userId,stockId);
            e.printStackTrace();
            return e.getMessage();

        }
    }


    /**
     * 乐观锁+redis+限流+隐藏接口token 实现秒杀
     * 限制单用户的访问频率
     * @param stockId
     * @return
     */
    @GetMapping("/kill6/{stockId}/{userId}/{md5Value}")
    public String kill6(@PathVariable("stockId") Integer stockId,
                        @PathVariable("userId") Integer userId,
                        @PathVariable("md5Value") String md5Value){

        if (!rateLimiter.tryAcquire(2, TimeUnit.SECONDS)){
            log.error("当前秒杀活动过于火爆，请重试！");
            return "抢购失败，请重试！";
        }

        try{

            int userCount = userService.getUserCount(userId);
            if (userCount > 10){
                log.error("请降低点击频率，稍后重试！");
                return "抢购失败，超出抢购频率，稍后重试！";
            }

            log.info("用户第{}次秒杀，商品的id:{}",userCount,stockId);
            Integer orderId = orderService.kill5(stockId,userId,md5Value);
            return "秒杀成功，订单id为:"+orderId;

        }catch (Exception e){

            log.error("用户{}秒杀商品id:{}时失败！",userId,stockId);
            e.printStackTrace();
            return e.getMessage();

        }
    }
}
